import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:logger/logger.dart';
import 'package:dio/dio.dart';
import 'dart:async';
import 'dart:io';
import './storage.dart';

export 'package:dio/dio.dart';
export './storage.dart';

// 日志输出
Logger logger = Logger(printer: PrettyPrinter());

// 消息提示
Future<bool?> showToast(String msg) {
  return Fluttertoast.showToast(msg: msg, toastLength: Toast.LENGTH_SHORT, gravity: ToastGravity.TOP, timeInSecForIosWeb: 1, backgroundColor: Colors.black54, textColor: Colors.white, fontSize: 14.0);
}

// 取消消息提示
Future<bool?> cancelToast() {
  return Fluttertoast.cancel();
}

// 配置模型
class DioConfig {
  bool logger; // 开启日志
  BaseOptions baseOptions; // dio配置参数
  Function unauthorizedHandler; // 未授权处理，如跳转登录
  List<int> unauthorizedStatusCodes; // 未授权状态码
  List<int> refreshTokenStatusCodes; // 刷新token状态码
  Future Function()? refreshTokenRequest; // 刷新token请求

  DioConfig({
    this.logger = true,
    required this.baseOptions,
    required this.unauthorizedHandler,
    this.unauthorizedStatusCodes = const [401],
    this.refreshTokenStatusCodes = const [402],
    this.refreshTokenRequest,
  });
}

class HttpUtil {
  static Dio? dio;
  static late DioConfig dioConfig; // 配置
  static bool _pending = false; // 等待请求中
  static final List _pendingList = []; // 待处理的请求
  static bool _processing = false; // 未授权处理中

  // 初始化
  static void initialization(DioConfig config) {
    dioConfig = config;
  }

  // Dio实例化
  static createInstance() async {
    if (dio != null) {
      return dio;
    }
    dio = Dio(dioConfig.baseOptions);
    // 拦截器、响应器、错误处理
    dio!.interceptors.add(
      InterceptorsWrapper(
        // 请求拦截器
        onRequest: (RequestOptions options, RequestInterceptorHandler handler) {
          options.headers['Authorization'] = getToken();
          return handler.next(options);
        },
        // 响应拦截器
        onResponse: (Response response, ResponseInterceptorHandler handler) async {
          // 日志输出
          if (dioConfig.logger) {
            logger.i({
              'url': '${response.requestOptions.baseUrl}${response.requestOptions.path}',
              'method': response.requestOptions.method,
              'statusCode': response.statusCode,
              'headers': response.requestOptions.headers,
              'queryParameters': response.requestOptions.queryParameters,
              'data': response.requestOptions.data,
              'response': response.data,
            });
          }
          // 响应成功
          if (response.data['code'] == 0 || response.data['code'] == null) {
            return handler.next(response);
          }
          // 短token过期，刷新token
          if (dioConfig.refreshTokenStatusCodes.contains(response.data['code'])) {
            Response res = await _refreshToken(response);
            return handler.next(res);
          }
          // 接口未授权
          if (dioConfig.unauthorizedStatusCodes.contains(response.data['code'])) {
            if (!_processing) {
              _processing = true;
              Timer(Duration(milliseconds: 1500), () {
                _processing = false;
              });
              dioConfig.unauthorizedHandler();
            }
          } else {
            showToast(response.data['msg'] ?? 'Dio Error');
          }
          return handler.reject(DioException(requestOptions: response.requestOptions, message: response.data['msg'] ?? 'Dio Error'));
        },
        onError: (DioException error, handler) async {
          showToast(error.message ?? 'Network Error');
          logger.e({
            'url': '${error.requestOptions.baseUrl}${error.requestOptions.path}',
            'method': error.requestOptions.method,
            'statusCode': error.response?.statusCode,
            'headers': error.requestOptions.headers,
            'queryParameters': error.requestOptions.queryParameters,
            'data': error.requestOptions.data,
            'response': error.response?.data,
            'message': error.message,
          }, error: 'Network Error');
          return handler.reject(DioException(requestOptions: error.requestOptions, message: error.message));
        },
      ),
    );
    return dio;
  }

  // 过期刷新token
  static Future<Response> _refreshToken(Response response) async {
    if (!_pending) {
      _pending = true;
      try {
        dioConfig.refreshTokenRequest!().then((res) async {
          // 释放所有等待
          _pending = false;
          for (var cb in _pendingList) {
            cb();
          }
          _pendingList.clear();
        });
      } catch (e) {
        _pending = false;
      }
    }
    final completer = Completer<Response>();
    // 存储所有等待
    _pendingList.add(() async {
      Response res = await _retry(response.requestOptions);
      completer.complete(res);
    });
    return completer.future;
  }

  // 请求接口重试
  static Future<Response> _retry(RequestOptions requestOptions) async {
    Dio dio = await createInstance();
    return dio.request(
      requestOptions.path,
      data: requestOptions.data,
      queryParameters: requestOptions.queryParameters,
      options: Options(
        method: requestOptions.method,
        headers: requestOptions.headers,
        extra: requestOptions.extra,
        responseType: requestOptions.responseType,
        contentType: requestOptions.contentType,
        followRedirects: requestOptions.followRedirects,
        validateStatus: requestOptions.validateStatus,
        receiveTimeout: requestOptions.receiveTimeout,
        sendTimeout: requestOptions.sendTimeout,
      ),
    );
  }
}

// GET请求-序列化JSON
Future<ResEntity<T>> getJSON<T>(
  String url,
  Map<String, dynamic>? queryParameters, {
  T Function(Map<String, dynamic>)? serialize, // 模型序列化的fromJson方法
  Options? options,
}) async {
  Dio dio = await HttpUtil.createInstance();
  Response response = await dio.get(url, queryParameters: queryParameters, options: options);
  Map<String, dynamic> result = response.data['data'] ?? {};
  if (serialize != null) {
    return ResEntity<T>.fromJson(response.data, serialize(result));
  }
  return ResEntity.fromJson(response.data);
}

// GET请求-序列化LIST
Future<ResEntity<List<T>>> getLIST<T>(
  String url,
  Map<String, dynamic>? queryParameters, {
  T Function(Map<String, dynamic>)? serialize, // 模型序列化的fromJson方法
  Options? options,
}) async {
  Dio dio = await HttpUtil.createInstance();
  Response response = await dio.get(url, queryParameters: queryParameters, options: options);
  List result = response.data['data'] ?? [];
  if (serialize != null) {
    List<T> entity = result.map((e) => serialize(e)).toList();
    return ResEntity<List<T>>.fromJson(response.data, entity);
  }
  return ResEntity.fromJson(response.data);
}

// GET请求-序列化PAGE
Future<ResEntity<Page<T>>> getPAGE<T>(
  String url,
  Map<String, dynamic>? queryParameters, {
  T Function(Map<String, dynamic>)? serialize, // 模型序列化的fromJson方法
  Options? options,
}) async {
  Dio dio = await HttpUtil.createInstance();
  Response response = await dio.get(url, queryParameters: queryParameters, options: options);
  Map<String, dynamic> result = response.data['data'] ?? {};
  if (serialize != null) {
    List list = result['list'] ?? [];
    List<T> entity = list.map((e) => serialize(e)).toList();
    return ResEntity<Page<T>>.fromJson(response.data, Page<T>.fromJson(result, entity));
  }
  return ResEntity<Page<T>>.fromJson(response.data);
}

// POST请求-序列化JSON
Future<ResEntity<T>> postJSON<T>(
  String url,
  Map<String, dynamic>? data, {
  T Function(Map<String, dynamic>)? serialize, // 模型序列化的fromJson方法
  Options? options,
}) async {
  Dio dio = await HttpUtil.createInstance();
  Response response = await dio.post(url, data: data, options: options);
  Map<String, dynamic> result = response.data['data'] ?? {};
  if (serialize != null) {
    return ResEntity<T>.fromJson(response.data, serialize(result));
  }
  return ResEntity.fromJson(response.data);
}

// 文件上传
Future<ResEntity<T>> uploadFile<T>(
  String url,
  Map<String, dynamic> data,
  File? file, {
  List<File>? files, // 多文件
  void Function(int, int)? onProgress, // 数据进度
  Function(Map<String, dynamic>)? serialize, // 模型序列化的fromJson方法
  Options? options,
}) async {
  Dio dio = await HttpUtil.createInstance();
  FormData formData = FormData.fromMap({...data, "file": file, "files": files});
  Response response = await dio.post(url, data: formData, options: options, onSendProgress: onProgress);
  dynamic result = response.data['data'] ?? {};
  if (serialize != null) {
    return ResEntity<T>.fromJson(response.data, serialize(result));
  }
  return ResEntity.fromJson(response.data);
}

// 文件下载
Future<void> downloadFile(
  String url,
  Map<String, dynamic>? queryParameters,
  dynamic savePath, {
  void Function(int, int)? onProgress, // 数据进度
  Function(Map<String, dynamic>)? serialize, // 模型序列化的fromJson方法
  Options? options,
}) async {
  Dio dio = await HttpUtil.createInstance();
  await dio.download(
    url,
    savePath,
    onReceiveProgress: onProgress, // 数据进度
    options: options ?? Options(responseType: ResponseType.bytes, followRedirects: false),
  );
}

// 请求响应模型
class ResEntity<T> {
  late int code;
  late String msg;
  late T data;
  ResEntity({required this.code, required this.msg, required this.data});

  ResEntity.fromJson(Map<dynamic, dynamic> json, [T? entity]) {
    code = int.tryParse(json['code']?.toString() ?? '') ?? 0;
    msg = json['msg']?.toString() ?? '';
    data = entity ?? json['data'];
  }
}

// 分页模型
class Page<T> {
  late int total;
  late List<T> list;

  Page({required this.total, required this.list});

  Page.fromJson(Map<dynamic, dynamic> json, [List<T>? entity]) {
    total = int.tryParse(json['total']?.toString() ?? '') ?? 0;
    list = entity ?? json["list"] ?? [];
  }
}
